<?php
namespace Phad\Test\Integration;
/**
* This class appears to test both form compilation and form submission
*
* @notice Several of these tests incidentally test the submit target/redirect feature.
*/
class Forms extends \Phad\Tester {
protected array $blogTableColumns = ['id'=>'INTEGER PRIMARY KEY','title'=>'VARCHAR(200)', 'body'=>'VARCHAR(2000)'];
public function testMultiplePdataNodes(){
$lildb = \Tlf\LilDb::sqlite();
$pdo = $lildb->pdo();
$phad = $this->phad();
$items = [];
$phad->handlers['item_initialized'] = function($ItemInfo) use (&$items){
$items[] = $ItemInfo;
};
$phad->pdo = $pdo;
$lildb->create('blog',['id'=>'integer', 'title'=>'varchar(90)', 'body'=>'varchar(90)']);
$lildb->insert('blog',['id'=>1,'title'=>'title 1','body'=>'body 1']);
$lildb->insert('blog',['id'=>2,'title'=>'title 2','body'=>'body 2']);
$lildb->insert('blog',['id'=>3,'title'=>'title 3','body'=>'body 3']);
$form = new \Phad\Item('Form/MultiPdata', $this->file('test/input/views/'),
['id'=>2, 'phad'=>$phad]);
$form->force_compile = true;
$this->str_contains($form,
"title 2"
);
// echo $form;
// exit;
// echo $form;
// echo "\n\n\n-----------\n\n";
$form = new \Phad\Item('Form/MultiPdata', $this->file('test/input/views/'),
['title'=>'title 3', 'phad'=>$phad]);
$form->force_compile = true;
/** @knownissue the type='default' p-data node does NOT work on forms when any other p-data nodes are present. If the issue is fixed, this should be changed to str_contains()
*/
$this->str_contains($form,
"title 3"
);
$this->str_not_contains($form,
"title 2"
);
// echo $form;
// exit;
$form = new \Phad\Item('Form/MultiPdata', $this->file('test/input/views/'),
['body'=>'body 1', 'phad'=>$phad]);
$form->force_compile = true;
$this->str_contains($form,
"body 1"
);
$this->str_not_contains($form,
"title 2"
);
}
public function testDeleteItem(){
$lildb = \Tlf\LilDb::sqlite();
$pdo = $lildb->pdo();
$phad = $this->phad();
$items = [];
$phad->handlers['item_initialized'] = function($ItemInfo) use (&$items){
$items[] = $ItemInfo;
};
$phad->pdo = $pdo;
$lildb->create('blog',['id'=>'integer', 'title'=>'varchar(90)']);
$lildb->insert('blog',['id'=>1,'title'=>'title 1']);
$lildb->insert('blog',['id'=>2,'title'=>'title 2']);
$lildb->insert('blog',['id'=>3,'title'=>'title 3']);
$form = new \Phad\Item('Form/Candelete', $this->file('test/input/views/'),
['id'=>2, 'phad'=>$phad]);
$form->force_compile = true;
$out = $form->delete();
echo $out;
print_r($items[0]->submit_errors);
$blogs = $lildb->select('blog');
$this->compare(
[ ['id'=>1,'title'=>'title 1'],
['id'=>3,'title'=>'title 3'],
],
$blogs
);
}
public function testErrorMessage(){
\Phad\TestHeaderHelper::$headers = [];
$pdo = $this->getPdo();
$phad = $this->phad();
$phad->router = $this->router();
$phad->pdo = $pdo;
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$BlogRow = ['body'=>'smol body', 'title'=>''];
$view = $phad->item('Form/SimpleBlogWithError', ['Blog'=>$BlogRow]);
$out = $view->submit();
$this->compare_lines(
$out,
<<<HTML
<form action="" method="POST">
<div class="my-error-class">
<p>'title' failed validation for 'required:true'</p>
<p>'body' failed validation for 'minlength:50'</p>
</div>
<input type="text" name="title" maxlength="75" required value="">
<textarea name="body" maxlength="2000" minlength="50">smol body</textarea>
</form>
HTML,
);
$this->test('Headers empty');
$this->compare(
[],
\Phad\TestHeaderHelper::$headers,
);
}
public function testSubmitDocumentation(){
\Phad\TestHeaderHelper::$headers = [];
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$ldb = \Tlf\LilDb::sqlite();
$pdo = $ldb->pdo();
$ldb->create('blog', $this->blogTableColumns);
$phad = $this->phad();
$phad->router = $this->router();
$phad->pdo = $pdo;
//if `id` were set, an UPDATE would be done instead.
$BlogRow = ['title'=>'Fine Title', 'body'=>'I have to be at least 50 characters. But that isn\'t very long.'];
$view = $phad->item('Form/SimpleBlogNoTarget', ['Blog'=>$BlogRow]);
$out = $view->submit();
$BlogRow['id'] = $pdo->lastInsertId();
$headers = \Phad\TestHeaderHelper::$headers;
//you can foreach(as $h){ header(...$h) }
//@export_end(Forms.ManualSubmission)
$this->test('Headers');
$this->compare(
// [['Location: https://localhost/', true]],
[],
$headers,
);
$this->test('Data Was Inserted');
$this->compare(
[$BlogRow],
$ldb->query('SELECT * FROM blog')
);
}
/**
* @test overriding onSubmit()
*/
public function testControllerOnSubmitDocumentation(){
\Phad\TestHeaderHelper::$headers = [];
$phad = new class() extends \Phad {
public function onSubmit($ItemInfo, &$ItemRow){
if ($ItemInfo->name!='Blog')return true;
$ItemRow['slug'] = str_replace(' ', '-', strtolower($ItemRow['title']));
return true;
}
};
$pdo = $this->getPdo();
$phad->exit_on_redirect = false;
$phad->force_compile = true;
$phad->item_dir = $this->file('test/input/views/');
$phad->router = $this->router();
$phad->pdo = $pdo;
$phad->target_url = '/blog/{slug}/{id}/';
$cols = $this->blogTableColumns;
$cols['slug'] = 'VARCHAR(100)';
$this->createTable($pdo, 'blog', $cols);
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$BlogRow =
[
'title'=>'Fine Title',
'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'
];
/** anonymous class to use as our controller */
/** passing our custom controller & submitting manually */
$view = $phad->item('Form/SimpleBlogNoTarget', ['Blog'=>$BlogRow]);
/** $BlogRow is just an array with 'title' & 'body' **/
$output = $view->submit();
$BlogRow['id'] = $pdo->lastInsertId();
$BlogRow['slug'] = 'fine-title';
$this->test('There should be no output');
$this->handleDidPass(strlen(trim($output))===0);
$this->test('Headers');
$this->compare(
[['Location: https://localhost/blog/fine-title/'.$BlogRow['id'].'/', true]],
\Phad\TestHeaderHelper::$headers,
);
$this->test('Data Was Inserted');
$this->compare(
$BlogRow,
$this->queryOne($pdo, 'SELECT * FROM blog'),
);
}
public function testWithInlineOnSubmit(){
\Phad\TestHeaderHelper::$headers = [];
$pdo = $this->getPdo();
$phad = $this->phad();
$phad->router = $this->router();
$phad->pdo = $pdo;
$phad->target_url = '/blog/{slug}/{id}/';
$cols = $this->blogTableColumns;
$cols['slug'] = 'VARCHAR(100)';
$this->createTable($pdo, 'blog', $cols);
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$BlogRow =
[
'title'=>'Fine Title',
'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'
];
$view = $phad->item('Form/BlogWithOnSubmit',['Blog'=>$BlogRow]);
$output = $view->submit();
$BlogRow['id'] = $pdo->lastInsertId();
$BlogRow['slug'] = 'fine-title';
$this->test('Backend Prop is removed');
$this->str_not_contains($phad->item('Form/BlogWithOnSubmit', $BlogRow), 'type="backend"');
$this->test('<onsubmit> tag was removed');
$this->str_not_contains($phad->item('Form/BlogWithOnSubmit', $BlogRow), '<onsubmit>');
$this->test('There should be no output');
$this->handleDidPass(strlen(trim($output))===0);
$this->test('Headers');
$this->compare(
[['Location: https://localhost/blog/fine-title/'.$BlogRow['id'].'/', true]],
\Phad\TestHeaderHelper::$headers,
);
$this->test('Data Was Inserted');
$this->compare(
$BlogRow,
$this->queryOne($pdo, 'SELECT * FROM blog'),
);
}
public function testInsertWithValidOption(){
\Phad\TestHeaderHelper::$headers = [];
$pdo = $this->getPdo();
$phad = $this->phad();
$phad->pdo = $pdo;
$phad->router = $this->router();
$cols = $this->blogTableColumns;
$cols['category'] = 'VARCHAR(100)';
$this->createTable($pdo, 'blog', $cols);
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$BlogRow = ['title'=>'Police Brutality super sucks', 'body'=>'Its been well documented that police brutality is a reality, yet there\'s still overwhelming controversy about what we should do with our society. Some say: Let the police to what they gotta do. Others say: Lets rethink this society that\'s built upon punishing people who misbehave & actually help people instead. Mayb ewe could redirect some of the MASSIVE tax dollars that go to police departments to actually help someone. That\'s me. I say that. - Reed',
'category'=>'Police Brutality'];
$view = $phad->item('Form/BlogWithCategories', ['Blog'=>$BlogRow]);
$out = $view->submit();
$BlogRow['id'] = $pdo->lastInsertId();
$this->test('There should be no output');
$this->handleDidPass(strlen(trim($out))===0);
$this->test('Headers');
$this->compare(
[['Location: https://localhost/blog/'.$BlogRow['title'].'/', true]],
\Phad\TestHeaderHelper::$headers,
);
$this->test('Data Was Inserted');
$this->compare(
$BlogRow,
$this->queryOne($pdo, 'SELECT * FROM blog'),
);
}
public function testUpdateValid(){
\Phad\TestHeaderHelper::$headers = [];
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$ldb = \Tlf\LilDb::sqlite();
$phad = $this->phad();
$phad->router = $this->router();
$phad->pdo = $ldb->pdo();
$ldb->create('blog', $this->blogTableColumns);
$BlogRow = ['id'=>0, 'title'=>'Fine Title', 'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'];
$ldb->insert('blog', $BlogRow);
$UpdatedBlog = $BlogRow;
$UpdatedBlog['title'] = 'New Title';
$view = $phad->item('Form/SimpleBlog',['Blog'=>$UpdatedBlog]);
$out = $view->submit();
$this->test('Headers');
$this->compare(
[['Location: https://localhost/blog/'.$UpdatedBlog['title'].'/', true]],
\Phad\TestHeaderHelper::$headers,
);
$this->test('Data Was Updated');
$this->compare(
[$UpdatedBlog],
$ldb->query('SELECT * FROM blog')
);
$this->test('No Output Present');
$this->compare(
'',
trim($out)
);
}
public function testInsertValid(){
\Phad\TestHeaderHelper::$headers = [];
$phad = $this->phad();
$phad->exit_on_redirect = false;
$phad->pdo = $this->getPdo();
$phad->router = $this->router();
$BlogRow = ['title'=>'Fine Title', 'body'=>'I have to be at least fifty characters. That shouldn\'t be much of a problem, though it does require a bit more typing. And if I had something original to say, that would make it better.'];
$view = $phad->item('Form/SimpleBlog', ['Blog'=>$BlogRow]);
$this->createTable($phad->pdo, 'blog', $this->blogTableColumns);
$_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTPS'] = 'non-empty-value';
$out = $view->submit();
$BlogRow['id'] = $phad->pdo->lastInsertId();
$this->test('There should be no output');
$this->handleDidPass(strlen(trim($out))===0);
var_dump($out);
$this->test('Headers');
$this->compare(
[['Location: https://localhost/blog/'.$BlogRow['title'].'/', true,]],
\Phad\TestHeaderHelper::$headers,
);
$this->test('Data Was Inserted');
$this->compare(
$BlogRow,
$this->queryOne($phad->pdo, 'SELECT * FROM blog'),
);
}
/**
* @test that a partially filled in form is returned when submission fails.
*/
public function testSubmitInvalid(){
$phad = $this->phad();
$phad->pdo = $this->pdo();
// $phad->pdo = new \PDO('sqlite:memory:?cache=w');
// $phad->force_compile = false;
$this->createTable($phad->pdo, 'blog', $this->blogTableColumns);
// View contains:
// <textarea name="body" maxlength="2000" minlength="50"></textarea>
$Blog = ['title'=>'Fine Title', 'body'=>'body too short'];
$view = $phad->item('Form/SimpleBlog', ['Blog'=>$Blog]);
// should fail because body is less than 50 chars
$out = $view->submit();
echo $out;
$this->test('Form cleaned up');
$this->str_not_contains($view, ['item=']);
$this->test('Submitted Blog Content');
$this->str_contains($out, 'value="'.$Blog['title'].'"');
$this->str_contains($out, '>'.$Blog['body'].'</textarea>');
}
public function testDisplayWithNoObject(){
$view = $this->item('Form/SimpleBlog');
// $Blog = ['title'=>'Fine Title', 'body'=>'body too short'];
$out = $view->html_with_no_data();
// $Blog = (object)$Blog;
$out = $view->html();
echo $out;
$this->test('Form cleaned up');
$this->str_not_contains($out, ['item=']);
$this->test('Target Attribute Removed');
$this->str_not_contains($out, 'target="');
$this->test('Submitted Blog Content');
$this->str_contains($out, 'value=""');
$this->str_contains($out, '></textarea>');
}
/**
* @test getting each selectable-option from a form's compiled view
*/
public function testHasSelectOptions(){
$view = $this->item('Form/BlogWithCategories');
$ItemInfo = $view->info();
$expect = [
'title' =>
[
'type' => 'text',
'maxlength' => '75',
'tagName' => 'input',
],
'body' =>
[
'maxlength' => '2000',
'minlength' => '50',
'tagName' => 'textarea',
],
'category'=>
[
'tagName'=> 'select',
'options'=>[
"social-justice",
"policy",
"Police Brutality",
"Election",
],
],
'id'=>
[
'tagName'=>'input',
'type'=>'hidden',
]
];
$this->compare($expect, $ItemInfo->properties);
}
/**
* @test getting info about properties from the compiled view.
*/
public function testHasPropertiesData(){
$view = $this->item('Form/SimpleBlog');
$ItemInfo = $view->info();
$expect = [
'title' =>
[
'type' => 'text',
'maxlength' => '75',
'tagName' => 'input',
],
'body' =>
[
'maxlength' => '2000',
'minlength' => '50',
'tagName' => 'textarea',
],
'id'=>
[
'tagName'=>'input',
'type'=>'hidden',
]
];
$this->compare($expect, $ItemInfo->properties);
}
public function item($name, $args=[]){
$phad = new \Phad();
$args['phad'] = $phad;
$item = new \Phad\Item($name, $this->file('test/input/views/'),$args);
$item->force_compile = true;
return $item;
}
public function phad($idk=null){
$phad = new \Phad();
$phad->exit_on_redirect = false;
$phad->force_compile = true;
$phad->item_dir = $this->file('test/input/views/');
return $phad;
}
public function pdo(){
return new \PDO("sqlite::memory:");
}
public function router(){
return new \Lia\Addon\Router();
}
}
namespace Phad;
class TestHeaderHelper{
static $headers = [];
}
function header(...$args){
TestHeaderHelper::$headers[] = $args;
}